package jp.co.nes.awssupport.test.utility;

import java.time.YearMonth;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.local.main.ServerRunner;
import com.amazonaws.services.dynamodbv2.local.server.DynamoDBProxyServer;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;

import jp.co.nes.awssupport.common.base.CommonException;
import jp.co.nes.awssupport.common.bean.CompileProgressBean;
import jp.co.nes.awssupport.common.bean.CompileProgressHeaderBean;
import jp.co.nes.awssupport.common.utility.AwsDynamoDBHelper;
import jp.co.nes.awssupport.common.utility.DateUtil;
import jp.co.nes.awssupport.common.utility.PropertiesUtil;

/**
 * JUnitで使用するDynamoDBローカルに関するユーティリティです。
 */
public class DynamoDBLocalUtil {

    /** DynamoDBProxyServer */
    private static DynamoDBProxyServer server = null;

    /**
     * デフォルトコンストラクタです。<br>
     * 本クラスはインスタンスを生成しません。
     */
    private DynamoDBLocalUtil() {
    }

    /**
     * DynamoDBローカルを開始します。
     */
    public static void start() {
        String dynamoDBLocalLibPath = PropertiesUtil.getProperty("DynamoDBLocalLibPath",
                "../awssupport/DynamoDBLocal_lib");
        System.setProperty("sqlite4java.library.path", dynamoDBLocalLibPath);
        String[] args = { "-inMemory" };
        try {
            server = ServerRunner.createServerFromCommandLineArgs(args);
            server.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 集計進捗状況ヘッダ、集計進捗状況に関するテーブルを作成します。
     */
    public static void createTableOfCompileProgress() {
        AwsDynamoDBHelper helper = new AwsDynamoDBHelper();
        helper.createTable(CompileProgressHeaderBean.class, 10, 10);
        helper.createTable(CompileProgressBean.class, 10, 10);
    }

    /**
     * 引数で指定された内容を、集計進捗状況ヘッダ、集計進捗状況に作成します。
     *
     * @param targetYearMonth 処理対象年月
     * @param linkedAccountIdList 連結アカウントIDリスト
     */
    public static void createCompileProgress(YearMonth targetYearMonth, List<String> linkedAccountIdList) {
        CompileProgressHeaderBean cphBean = new CompileProgressHeaderBean();
        cphBean.setTargetYearMonth(targetYearMonth);

        List<CompileProgressBean> cpList = new ArrayList<>();
        for (String linkedAccountId : linkedAccountIdList) {
            CompileProgressBean cpBean = new CompileProgressBean();
            cpBean.setTargetYearMonth(targetYearMonth);
            cpBean.setLinkedAccountId(linkedAccountId);
            cpList.add(cpBean);
        }

        AwsDynamoDBHelper helper = new AwsDynamoDBHelper();
        helper.save(cphBean);
        cpList.stream().forEach(bean -> helper.save(bean));
    }

    /**
     * 引数で指定された内容を、集計進捗状況ヘッダ、集計進捗状況に作成します。
     *
     * @param targetYearMonth 処理対象年月
     * @param linkedAccountIdList 集計進捗状況リスト
     */
    public static void createCompileProgressByList(YearMonth targetYearMonth, List<CompileProgressBean> cpList) {
        CompileProgressHeaderBean cphBean = new CompileProgressHeaderBean();
        cphBean.setTargetYearMonth(targetYearMonth);

        AwsDynamoDBHelper helper = new AwsDynamoDBHelper();
        helper.save(cphBean);
        cpList.stream().forEach(bean -> helper.save(bean));
    }

    /**
     * 集計進捗状況ヘッダ、集計進捗状況の内容を削除します。
     */
    public static void deleteCompileProgress() {
        AwsDynamoDBHelper helper = new AwsDynamoDBHelper();
        {
            List<CompileProgressHeaderBean> scanList = helper.scan(CompileProgressHeaderBean.class,
                    new DynamoDBScanExpression());
            if (scanList == null) {
                scanList = new ArrayList<>();
            }
            scanList.stream().forEach(bean -> helper.delete(bean));
        }
        {
            List<CompileProgressBean> scanList = helper.scan(CompileProgressBean.class, new DynamoDBScanExpression());
            if (scanList == null) {
                scanList = new ArrayList<>();
            }
            scanList.stream().forEach(bean -> helper.delete(bean));
        }
    }

    /**
     * 引数で指定された処理対象年月の集計進捗状況ヘッダの確定フラグを設定します。
     *
     * @param targetYearMonth 処理対象年月
     * @param isConfirmedBillingCsv 確定フラグ
     */
    public static void confirmedBillingCsv(YearMonth targetYearMonth, boolean isConfirmedBillingCsv) {
        CompileProgressHeaderBean cphBean = get(targetYearMonth);
        cphBean.setConfirmedBillingCsv(isConfirmedBillingCsv);

        AwsDynamoDBHelper helper = new AwsDynamoDBHelper();
        helper.save(cphBean);
    }

    /**
     * DynamoDBローカルを停止します。
     */
    public static void stop() {
        if (server != null) {
            try {
                server.stop();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 引数に該当する集計進捗状況ヘッダを返却します。<br>
     * 該当データが存在しない場合は、nullを返却します。
     *
     * @param targetYearMonth 処理対象年月
     * @return 集計進捗状況ヘッダ
     */
    private static CompileProgressHeaderBean get(YearMonth targetYearMonth) {
        String keyConditionExpression = "targetYearMonth = :targetYearMonth";
        DynamoDBQueryExpression<CompileProgressHeaderBean> queryExpression = new DynamoDBQueryExpression<>();
        queryExpression.setKeyConditionExpression(keyConditionExpression);

        Map<String, AttributeValue> attrValMap = new HashMap<>();
        attrValMap.put(":targetYearMonth", new AttributeValue().withS(DateUtil.toString(targetYearMonth)));
        queryExpression.setExpressionAttributeValues(attrValMap);

        // queryは条件にプライマリキーの設定が必要。
        CompileProgressHeaderBean result = null;
        AwsDynamoDBHelper helper = new AwsDynamoDBHelper();
        List<CompileProgressHeaderBean> queryList = helper.query(CompileProgressHeaderBean.class, queryExpression);
        if (queryList != null && !queryList.isEmpty()) {
            int size = queryList.size();
            if (size == 1) {
                result = queryList.get(0);
            } else {
                throw new CommonException("queryList is wrong(size=" + size + ")");
            }
        }
        return result;
    }
}
